PopupMenu = new Class ({
    Implements: [Events, Options],
    options: {
        onOpen: $empty,
        onSelect: $empty,
        cursorX: 2,
        cursorY: 1,
        offsetX: 0,
        offsetY: 0,
        opacity: 0.95
    },
    
    initialize: function (menuId,options) {
        this.setOptions (options);
        this.menu = $(menuId);
        
        this.menu.setStyles ({ 
            'position': 'absolute',
            'z-index': 99
        });
        
	    $$('#'+menuId+' a').each(function(link) {
            var href = link.get('href');
	        link.set('hrefBack',href);
        });
        this.open = this.open.bindWithEvent(this);
        this.close = this.close.bind(this);
        this.preOpenEvent = this.preOpenEvent.bind(this)
        this.menuEvent = this.menuEvent.bindWithEvent(this);
        
        this.clickedElement = $empty;
        
        this.menuTree = new MenuTree(this.menu.getElement('ul'),null);
    },
    open: function (event) {         
        var coords = {
            y:event.page.y + this.options.cursorY,
            x:event.page.x + this.options.cursorX
        };
        this.menu.getPosition().y-$(document.body).getScroll().y+this.menu.getSize().y < $(document.body).getSize().y ?
            coords.y = event.page.y + this.options.cursorY :
            coords.y = event.page.y - this.menu.getSize().y + this.options.cursorY;
        if (coords.y<$(document.body).getScroll().y+1) coords.y = $(document.body).getScroll().y+1;
        this.menu.getPosition().x-$(document.body).getScroll().x+this.menu.getSize().x < $(document.body).getSize().x ?
            coords.x = event.page.x + this.options.cursorX :
            coords.x = event.page.x - this.menu.getSize().x + this.options.cursorX;
        if (coords.x<$(document.body).getScroll().x+1) coords.x = $(document.body).getScroll().x+1;
        if (event.shift) coords.x = event.page.x - this.menu.getSize().x - this.options.cursorX;
        this.menu.setStyles({
	        top: coords.y-this.options.offsetY,
	        left: coords.x-this.options.offsetX,
	        visibility: 'visible'
	    });
        //this.menu.fade(this.options.opacity);
	    
        window.addEvent('blur', function () { if (!Browser.Engine.trident) this.close() }.bind(this)); //ie throws currious blur events
        document.addEvent ('mousedown', this.menuEvent);
        
        this.menu.addEvents({
            'contextmenu': $lambda(false),
            'mouseup': this.menuEvent
        });
        this.fireEvent('onOpen', event);
	    this.updateHref();
    },
    updateHref: function() {
	    var extraQueryString = this.getExtraQueryString();
        if (!extraQueryString) {
            extraQueryString = "";
        }else {
            extraQueryString = extraQueryString.trim();
        }
        var emptyQuery = true;
        if (extraQueryString != "") {
            emptyQuery = false;
        }
	    $$('#'+this.menu.get('id')+' a').each(function(link) {
            var href = link.getProperty('hrefBack');
            var tmpQuery = extraQueryString;
            if (href.indexOf('javascript:') != -1 ) {
                tmpQuery = "";
            }else if (href.indexOf('?')==-1 && !emptyQuery) {
                href += '?';
            }else if (href.indexOf('=') != -1 && !emptyQuery ) {
                href += '&';
            }
            if (link.hasClass('disabled')) {
                link.set('href','javascript:void(0)');
            }else {
                link.set('href',href+tmpQuery);
            }
        });
    },
    preOpenEvent: function (event) {  
	    event.preventDefault();
	    if (this.menu.getStyle('visibility') == 'visible') this.close(event);
	    
	    this.clickedElement = $(event.target);
	    
	    if (event.rightClick) {
            this.open(event);
	    }else {
	        return true;
	    }
	    return false;        
    },
    menuEvent: function (event) { 
        event.preventDefault();
        
        var item = $(event.target);
        if (item == this.menu || item == this.menu.getElement('ul')) return false; 
	    item = this.ascendTo(item,['item','separator']);
        if (item==false) {
            this.close(event); //outer event
        } else if (item.hasClass('item') && event.type == 'mouseup' ) {
            this.close(event); 
        }
    },    
    
    close: function (event) {
        //this.menu.fade('out');
	    this.menu.setStyle('visibility','hidden');
        
        document.removeEvent ('mousedown', this.menuEvent);
        window.removeEvent ('blur', function () {if (!Browser.Engine.trident) this.close()}.bind(this));
        this.menu.removeEvents();
    },
    ascendTo: function (el, peakto) {
        if (el == window) return false;
        var ascel = el;
        while (ascel.get('tag') != 'html') { 
            for (var i=0; i<peakto.length; i++) {
                if (ascel.get('tag')=='li' &&
		            ascel.hasClass(peakto[i])) {
		            return ascel;
		        }
            }
            ascel = ascel.getParent(); 
        }
        return false;        
    },
    enableItems: function (items, enable) {
        if (!$chk(items) && items!=false) items = true;
        if ($type(items) == 'boolean') {
            this.menu.getElements ('li.item a').each(function (item){
                if (items) {
                    item.removeClass('disabled');
                }else {
                    addClass('disabled');
                }
            });
            return;
        }
        
        if (!$chk(enable) && enable!=false) enable = true;
        if ($type(items) == 'string') items = [items];
        
        items.each (function (item) {
            if (enable) {
                this.menu.getElement('li#'+item+' a').removeClass('disabled');
            }else {
                this.menu.getElement('li#'+item+' a').addClass('disabled');
            }
        }.bind(this));
    },
    attachElement: function(element) {
	    if ($defined(element.getElement)) {
	        element = element.getElement();
	    }
	    if ($type(element)=='string'||
	        $type(element)=='document') { 
	        element = $(element);
	    }
	    element.addEvents ({
            'mousedown': function (event) {element.addEvent ('contextmenu', function() {
		        if ($defined(element.dragMove)) {
		            element.dragMove.cancel();
		        }
		        return false;
	        })}.bind(this),
            'mouseup': function(event) {
		        if ($defined(element.dragMove)) {
		            element.dragMove.cancel();
		        }
		        this.preOpenEvent(event);
	        }.bind(this)
	    });
	    element.getParent().addEvent ('mousedown', this.menuEvent);
    },
    getExtraQueryString: function(element) {
        return "";
    }
});
    
    
    MenuTree = new Class({
        initialize: function (ulEl,parent) {
            this.parent = parent;
	        this.ulEl = ulEl;
            var items = ulEl.getChildren();
            var subMenus = new Hash();
	        var thisIsMe = this;
	        var ulSize = ulEl.getSize();
	        this.ulEl.addEvents({
		        'contextmenu': $lambda(false)
	        });
	        
            items.each(function(item,index) {
		        if (item.hasClass('separator') ||
		            item.hasClass('item') ) {
		            item.setStyle('width',ulSize.x+'px');
		        }

		        var subUlEl = item.getElement('ul');
                if (subUlEl) {
		            var subUlSize = subUlEl.getSize();
		            subUlEl.setStyles({
			            'position':'absolute',
			            'visibility':'hidden',
			            'z-index':100
		            });
                    subMenus.set(index,new MenuTree(subUlEl,thisIsMe));
		            var anchor =  item.getElement('a');
		            if (anchor) {
			            var span = new Element('span',{
			                'text':'>',
			                styles: {
				                'position':'relative',
				                'display':'inline',
				                'float':'right',
				                'white-space':'pre',
				                'font-weight':'bold'
			                }
			            });
			            span.inject(anchor,'before');
		            }

		            item.addEvents({
			            'mouseover':function(event) {
			                var coord = item.getCoordinates();
			                var ulPos = ulEl.getPosition();
			                subUlEl.setStyles({
				                'left':(coord.right-ulPos.x+3)+'px',
				                'top':(coord.top-ulPos.y)+'px'
			                });
			                subUlEl.fade('in');
			            },
			            'mouseout':function(event) {
			                subUlEl.fade('out');
			            }
		            });
                }
            });
	        this.items = items;
	        this.subMenus = subMenus;
        }
    });
